package ru.vsu.amm.calculus;

/**
 * 
 * @author Атякшин Фёдор
 *
 */
public class ThreeTwoDimensionalMatrix {
	
	private int[][] MDisplacment;
	private int[][] TableAdjacency;
	private int L;
	
	private ThreeTwoDimensionalMatrix() {}
	
	public int[][] getMDisplacment() {
		return MDisplacment;
	}
	
	public int[][] getTableAdjacency() {
		return TableAdjacency;
	}
	
	public int getL() {
		return L;
	}
	
	public static ThreeTwoDimensionalMatrix calculate(Integer Nx, Integer Ny, Integer Nz) {
		ThreeTwoDimensionalMatrix res = new ThreeTwoDimensionalMatrix();
		
		int n = 0; // Current number of node
		
		// Matrix of relative displacement. 
		// Origin of  space is started in left bottom corner like on third picture  in task
		res.MDisplacment = new int[(Nx + 1) * (Ny + 1) * (Nz + 1)][3];
		
		// Mon= MatrixOfNumeration. Mon[3,5,7]=24 means that if we make three steps 
		// on X axis, Then five steps on Y, and seven on Z, there willbe the node number 24.
		int[][][] Mon = new int[Nx + 1][Ny + 1][Nz + 1]; 
		for (int ix = 0; ix <= Nx; ix++)
			for (int iy = 0; iy <= Ny; iy++)
				for(int iz = 0; iz <= Nz; iz++) {
					res.MDisplacment[n][0]=ix;
					res.MDisplacment[n][1]=iy;
					res.MDisplacment[n][2]=iz;
					Mon[ix][iy][iz] = n++;
				}
		
		//Loop on each parallelepiped and exctract from each Six tetrahedrons. The order of points on tetrahedrons as in "Zenkevich"
		
		res.TableAdjacency = new int[Nx * Ny * Nz * 6][4];
		
		int tetrIndex = 0; 
		for (int Nbx = 0; Nbx < Nx; Nbx++)
			for (int Nby = 0; Nby < Ny; Nby++)
				for ( int Nbz = 0; Nbz < Nz; Nbz++) {
					// untranslatable Russian folklore
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx + 1][Nby    ][Nbz + 1];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx    ][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx + 1][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx + 1][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx    ][Nby + 1][Nbz    ];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx + 1][Nby + 1][Nbz    ];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx + 1][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx + 1][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx    ][Nby + 1][Nbz    ];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx + 1][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx    ][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx + 1][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx    ][Nby    ][Nbz + 1];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx    ][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx + 1][Nby    ][Nbz + 1];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx    ][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx + 1][Nby    ][Nbz    ];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx + 1][Nby    ][Nbz + 1];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx    ][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx    ][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
					
					res.TableAdjacency[tetrIndex][0] = Mon[Nbx + 1][Nby    ][Nbz    ];
					res.TableAdjacency[tetrIndex][1] = Mon[Nbx    ][Nby + 1][Nbz + 1];
					res.TableAdjacency[tetrIndex][2] = Mon[Nbx    ][Nby + 1][Nbz    ];
					res.TableAdjacency[tetrIndex][3] = Mon[Nbx    ][Nby    ][Nbz    ];
					res.updateL(tetrIndex++);
				}
		
		res.L++;
		
		return res;
	}//end main
	
	private void updateL(int index){
		int[] array = TableAdjacency[index];
		for (int i = 0; i < array.length; i++)
			for (int j = i + 1; j < array.length; j++)
				L = Math.max(L, Math.abs(array[i]-array[j]));
	}
}